package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.zzyl.constant.DeptCacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.DeptDto;
import com.zzyl.entity.Dept;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.PostMapper;
import com.zzyl.service.DeptService;
import com.zzyl.service.UserService;
import com.zzyl.utils.BeanConv;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeptVo;
import com.zzyl.vo.TreeItemVo;
import com.zzyl.vo.TreeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 部门表服务实现类
 */
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Resource
    private PostMapper postMapper;

    @Autowired
    private UserService userService;

    /**
     * @param deptDto 对象信息
     * @return DeptVo
     *  创建部门
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = DeptCacheConstant.LIST, allEntries = true),
            @CacheEvict(value = DeptCacheConstant.TREE, allEntries = true)
    })
    public Boolean createDept(DeptDto deptDto) {
        //转换deptDto为Dept
        Dept dept = BeanUtil.toBean(deptDto, Dept.class);

        //根据传递过来的父部门编号创建当前部门编号
        String deptNo = createDeptNo(dept.getParentDeptNo());
        dept.setDeptNo(deptNo);

        //保存
        int flag = deptMapper.insert(dept);
        if (flag != 1) {
            throw new RuntimeException("保存部门信息出错");
        }

        //如果当前leader也是其他部门的负责人，则清空其他部门的leader数据
        //一个人只能是一个部门的leader
        if (ObjectUtil.isNotEmpty(deptDto.getLeaderId())) {
            //根据leader查询，如果存在，则清空
            deptMapper.clearOtherDeptLeader(deptDto.getLeaderId(), deptNo);
            //在用户表设置标识，表明当前部门的leader
            userService.updateIsLeaderByUserIdAndDeptNo(deptDto.getLeaderId(), deptNo);
        }

        return true;
    }

    /**
     * @param deptDto 对象信息
     * @return Boolean
     *  修改部门表
     */
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = DeptCacheConstant.LIST, allEntries = true),
            @CacheEvict(value = DeptCacheConstant.TREE, allEntries = true)
    })
    @Override
    public Boolean updateDept(DeptDto deptDto) {
        //转换DeptDto为Dept
        Dept dept = BeanUtil.toBean(deptDto, Dept.class);

        //检验是否可以修改
        if (dept.getDataState().equals("1")) {
            if (hasChildByDeptId(dept.getDeptNo())) {
                throw new RuntimeException("存在下级部门,不允许禁用");
            }
            if (checkDeptExistUser(dept.getDeptNo())) {
                throw new RuntimeException("部门存在用户,不允许禁用");
            }
        }

        //修改
        int flag = deptMapper.updateByPrimaryKey(dept);
        if (flag == 0) {
            throw new RuntimeException("修改部门信息出错");
        }

        //如果当前leader也是其他部门的负责人，则清空其他部门的leader数据
        //一个人只能是一个部门的leader
        if (ObjectUtil.isNotEmpty(deptDto.getLeaderId())) {
            //根据leader查询，如果存在，则清空
            deptMapper.clearOtherDeptLeader(deptDto.getLeaderId(), deptDto.getDeptNo());
            //在用户表设置标识，表明当前部门的leader
            userService.updateIsLeaderByUserIdAndDeptNo(deptDto.getLeaderId(), dept.getDeptNo());
        }

        return true;
    }

    /**
     * @param deptDto 查询条件
     *  多条件查询部门列表
     * @return: List<DeptVo>
     */
    @Cacheable(value = DeptCacheConstant.LIST, key ="#deptDto.hashCode()")
    @Override
    public List<DeptVo> findDeptList(DeptDto deptDto) {
        List<Dept> deptList = deptMapper.selectList(deptDto);
        if (CollUtil.isEmpty(deptList)) {
            return Collections.emptyList();
        }
        List<DeptVo> deptVos = BeanConv.toBeanList(deptList, DeptVo.class);
        deptVos.forEach(v -> v.setCreateDay(LocalDateTimeUtil.format(v.getCreateTime(), DatePattern.NORM_DATE_FORMATTER)));
        return deptVos;
    }


    @Override
    public List<DeptVo> findDeptInDeptNos(List<String> deptNos) {
        List<Dept> depts = deptMapper.findDeptInDeptNos(deptNos);
        return BeanConv.toBeanList(depts, DeptVo.class);
    }


    @Override
    public String createDeptNo(String parentDeptNo) {
        if (NoProcessing.processString(parentDeptNo).length() / 3 == 5) {
            throw new BaseException("部门最多4级");
        }
        DeptDto deptDto = DeptDto.builder().parentDeptNo(parentDeptNo).build();
        List<Dept> deptList = deptMapper.selectList(deptDto);
        //无下属节点则创建下属节点
        if (EmptyUtil.isNullOrEmpty(deptList)) {
            return NoProcessing.createNo(parentDeptNo, false);
            //有下属节点则累加下属节点
        } else {
            Long deptNo = deptList.stream()
                    .map(dept -> Long.valueOf(dept.getDeptNo()))
                    .max(Comparator.comparing(Function.identity())).get();
            return NoProcessing.createNo(String.valueOf(deptNo), true);
        }
    }

    @Override
    public List<DeptVo> findDeptVoListInRoleId(List<Long> roleIdSet) {
        return deptMapper.findDeptVoListInRoleId(roleIdSet);
    }

    @Caching(evict = {
            @CacheEvict(value = DeptCacheConstant.LIST, allEntries = true),
            @CacheEvict(value = DeptCacheConstant.TREE, allEntries = true)
    })
    @Override
    public int deleteDeptById(String deptId) {
        Dept dept = deptMapper.selectByDeptNo(deptId);
        if (ObjectUtil.isNull(dept)) {
            throw new BaseException("部门不存在");
        }
        if (ObjectUtil.equals(dept.getDataState(), "0")) {
            throw new BaseException("启用状态下不可删除");
        }
        // 判断是否有子部门
        if (hasChildByDeptId(deptId)) {
            // 有子部门
            throw new BaseException("存在下级部门,不允许删除");
        }
        return deptMapper.deleteByDeptNo(deptId);
    }

    /**
     * 启用-禁用部门
     *
     * @param deptDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
            @CacheEvict(value = DeptCacheConstant.LIST, allEntries = true),
            @CacheEvict(value = DeptCacheConstant.TREE, allEntries = true)
    })
    public Boolean isEnable(DeptDto deptDto) {
        Dept deptDB = deptMapper.getByDeptNo(deptDto.getDeptNo());
        if (ObjectUtil.isNull(deptDB)) {
            throw new BaseException("部门不存在");
        }

        if ("0".equals(deptDto.getDataState())) {
            // 获取父级部门
            Dept parentDept = deptMapper.getByDeptNo(deptDB.getParentDeptNo());

            if (ObjectUtil.isNotNull(parentDept)) {
                // 父级部门为禁用状态，子部门不允许启用
                if (ObjectUtil.equal(parentDept.getDataState(), "1")) {
                    throw new BaseException("父级部门为禁用状态，不允许启用");
                }
            }
        }
        Dept dept = new Dept();
        dept.setDataState(deptDto.getDataState());
        dept.setId(deptDB.getId());
        deptMapper.updateByPrimaryKey(dept);
        List<Dept> childrenDeps = deptMapper.getChildren(deptDB.getDeptNo());

        // 判断是否存在子部门
        if (CollectionUtil.isNotEmpty(childrenDeps)) {
            childrenDeps.forEach(item -> {
                // 递归调用
                DeptDto dto = DeptDto.builder()
                                .deptNo(item.getDeptNo())
                                .dataState(deptDto.getDataState())
                                .parentDeptNo(item.getParentDeptNo())
                                .build();
                this.isEnable(dto);
            });
        }
        return true;
    }

    /**
     * 是否存在子节点
     *
     * @param deptId 部门ID
     * @return 结果
     */
    public boolean hasChildByDeptId(String deptId) {
        int result = deptMapper.hasChildByDeptId(deptId);
        return result > 0;
    }

    /**
     * 查询部门是否存在用户
     *
     * @param deptId 部门ID
     * @return 结果 true 存在 false 不存在
     */
    public boolean checkDeptExistUser(String deptId) {
        int result = deptMapper.checkDeptExistUser(deptId);
        return result > 0;
    }

    /**
     * 组织部门树形
     * @return: deptDto
     */
    @Override
    @Cacheable(value = DeptCacheConstant.TREE)
    public TreeVo deptTreeVo() {
        // 根节点查询树形结构
        String parentDeptNo = SuperConstant.ROOT_DEPT_PARENT_ID;
        // 指定节点查询树形结构
        DeptDto deptDto = DeptDto.builder()
                .dataState(SuperConstant.DATA_STATE_0)
                .parentDeptNo(NoProcessing.processString(parentDeptNo))
                .build();
        // 查询部门列表数据
        List<Dept> deptList =  deptMapper.selectList(deptDto);

        if (CollectionUtil.isEmpty(deptList)) {
            return new TreeVo();
        }
        // 返回的部门列表
        List<TreeItemVo> treeItemVoList = new ArrayList<>();
        // 获取根节点
        deptList.stream()
                .filter(dept -> ObjectUtil.equal(dept.getParentDeptNo(), SuperConstant.ROOT_DEPT_PARENT_ID))
                .findFirst()
                .ifPresent(rootDept -> this.recursionTreeItem(treeItemVoList, rootDept, deptList));
        // 返回结果
        return TreeVo.builder()
                .items(treeItemVoList)
                .build();
    }

    /**
     * 构建树形结构，递归调用
     * @param treeItemVoList   封装返回的对象
     * @param deptRoot  当前部门
     * @param deptList  部门列表（全部数据）
     */
    private void recursionTreeItem(List<TreeItemVo> treeItemVoList, Dept deptRoot, List<Dept> deptList) {
        //根部门对象 智慧养老院
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(deptRoot.getDeptNo())
                .label(deptRoot.getDeptName())
                .build();
        //获取当前部门的子部门
        List<Dept> childrenDept = deptList.stream().filter(dept -> ObjectUtil.equals(dept.getParentDeptNo(), deptRoot.getDeptNo()))
                        .collect(Collectors.toList());
        //如果子部门不为空，则继续递归调用
        if (CollUtil.isNotEmpty(childrenDept)) {
            // 智慧养老院树形子部门集合
            List<TreeItemVo> listChildren = new ArrayList<>();
            childrenDept.forEach(dept -> this.recursionTreeItem(listChildren, dept, deptList));
            treeItemVo.setChildren(listChildren);
        }
        treeItemVoList.add(treeItemVo);
    }
}
